# !/usr/bin/env python
# -*-coding:utf-8 -*-

"""
# File       : orderlines_export_view.py
# Time       ：2023/8/28 15:19
# Author     ：YangYong
# version    ：python 3.10
# Description：导出流程报告
"""
import json
import os
from typing import List
from datetime import datetime
from urllib.parse import quote

import pandas as pd
from flask import current_app, make_response, send_file
from jinja2 import FileSystemLoader, Environment

from apis.orderlines import orderlines_ns
from apis.orderlines.models import ProcessInstance, TaskInstance
from apis.orderlines.schema.process_schema import ProcessInstanceExportScheme
from apis.orderlines.schema.task_schema import TaskInstanceExportSchema
from public.api_utils.api_decorator import handle_api_error
from public.base_model import db
from public.base_view import AbstractView


class ProcessInstanceHtmlReportView(AbstractView):
    url = '/process_export'

    def __init__(self, *args, **kwargs):
        super(ProcessInstanceHtmlReportView, self).__init__(*args, **kwargs)
        self.file_name = f'{datetime.now().strftime("%Y-%m-%d")}.html'
        self.html_file_path = None
        self.process_instance_id = self.form_data.get('process_instance_id')
        self.is_logger = True
        self.exclude = []

    def get_node(self, value: str, nodes: List[dict], is_task_id: bool = False) -> dict:
        for node in nodes:
            if node.get('task_id') == value and is_task_id:
                return node
            elif node.get('task_instance_id') == value and not is_task_id:
                return node
        return {}

    def handle_parallel_tasks(self, parallel_task: dict, nodes: List[dict]):
        """处理并行节点"""
        method_kwargs = json.loads(parallel_task.get('method_kwargs'))
        parallel_task_ids = method_kwargs.get('parallel_task_ids')
        children = []
        for parallel_task_id in parallel_task_ids:
            group_task = self.get_node(parallel_task_id, nodes, is_task_id=True)
            self.handle_group_task(group_task, nodes)
            children.append(group_task)
        return children

    def handle_group_task(self, group_task: dict, nodes: List[dict]):
        """处理任务节点"""
        method_kwargs = json.loads(group_task.get('method_kwargs'))
        group_ids = method_kwargs.get('group_ids')
        children = []
        for task_id in group_ids:
            common_task = self.get_node(task_id, nodes, is_task_id=True)
            children.append(common_task)
        return children

    def handle_sub_process(self, sub_process: dict):
        """处理子流程"""
        method_kwargs = json.loads(sub_process.get('method_kwargs'))
        sub_process_id = method_kwargs.get('sub_process_id')
        with db.auto_commit():
            objs = db.session.query(TaskInstance).filter(
                TaskInstance.process_id == sub_process_id,
                TaskInstance.process_instance_id == self.process_instance_id,
                TaskInstance.active == 1
            ).all()
            sub_task_instances = TaskInstanceExportSchema().dump(objs, many=True)

            return self.handle_node(sub_task_instances)

    def handle_node(self, nodes: list):
        """获取节点的子节点"""
        task_instances = []
        for node in nodes:
            if node.get('method_name') == 'parallel_task':
                parallel_children = self.handle_parallel_tasks(node, nodes)
                node['children'] = parallel_children
            elif node.get('method_name') == 'task_group':
                group_children = self.handle_group_task(node, nodes)
                node['children'] = group_children
            elif node.get('method_name') == 'sub_process':
                node['children'] = self.handle_sub_process(node)

            if node.get('task_instance_id') not in self.exclude:
                task_instances.append(node)
                self.exclude.append(node.get('task_instance_id'))
        return task_instances

    def get_response(self):
        process_instance_obj = db.session.query(ProcessInstance).filter(
            ProcessInstance.process_instance_id == self.process_instance_id).first()

        process_instance_info = ProcessInstanceExportScheme().dump(process_instance_obj)

        task_instance_obj = db.session.query(TaskInstance).filter(
            TaskInstance.process_instance_id == self.process_instance_id).all()

        task_instance_info = TaskInstanceExportSchema().dump(task_instance_obj, many=True)
        df = pd.DataFrame(task_instance_info)
        response_data = dict()
        task_instance_info: list = df.to_dict('records')
        self.file_name = f'{process_instance_info.get("process_name")}_{self.file_name}'
        self.html_file_path = os.path.join(current_app.template_folder, self.file_name)
        response_data['process_instance_info'] = process_instance_info
        task_instances = self.handle_node(task_instance_info)
        response_data['task_instance_info'] = task_instances
        return response_data

    def generate_html(self, data):
        env = Environment(loader=FileSystemLoader(current_app.template_folder))
        template = env.get_template('template.html')
        with open(self.html_file_path, 'w+', encoding='utf-8') as f:
            out = template.render(**data)
            f.write(out)
            f.close()

    @handle_api_error()
    @orderlines_ns.doc(description="导出流程报告")
    def post(self):
        """导出流程报告"""
        data = self.get_response()
        self.generate_html(data)
        response = make_response(send_file(self.html_file_path))
        response.headers["Content-Disposition"] = f"attachment; filename={quote(self.file_name)};"
        return response
